# coding=utf-8
# http://python.jobbole.com/85231/
"""
1 Python的函数参数传递
所有的变量都可以理解是内存中一个对象的“引用”，或者，也可以看似c中void*的感觉。

这里记住的是类型是属于对象的，而不是变量。而对象有两种,“可更改”（mutable）与“不可更改”（immutable）对象。在python中，
strings, tuples, 和numbers是不可更改的对象，而list,dict等则是可以修改的对象。(这就是这个问题的重点)
当一个引用传递给函数的时候,函数自动复制一份引用,这个函数里的引用和外边的引用没有半毛关系了.
所以第一个例子里函数把引用指向了一个不可变对象,当函数返回的时候,外面的引用没半毛感觉.
而第二个例子就不一样了,函数内的引用指向的是可变对象,对它的操作就和定位了指针地址一样,在内存里进行修改.
可变数据类型：列表list和字典dict；不可变数据类型：整型int、浮点型float、字符串型string和元组tuple。
"""

a = 1
def fun(a):
    a = 2
fun(a)
print a  # 1

a = []
def fun(a):
    a.append(1)
fun(a)
print a  # [1]

"""
Python中的元类(metaclass)
http://python.jobbole.com/21351/
元类可以动态修改类

"""

"""
3 @staticmethod和@classmethod
"""


def foo(x):
    print "executing foo(%s)" % (x)


class A(object):
    def foo(self, x):
        print "executing foo(%s,%s)" % (self, x)

    @classmethod
    def class_foo(cls, x):
        print "executing class_foo(%s,%s)" % (cls, x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)" % x


a = A()
a.foo('shilifangfa')
a.class_foo('class fangfa')
a.static_foo('static fangfa')
# A.foo('shili fangfa2')  # 类不可调用实例方法
A.class_foo('class fangfa2')
A.static_foo('static fangfa2')
'''
executing foo(<__main__.A object at 0x00000000039AD7B8>,shilifangfa)
executing class_foo(<class '__main__.A'>,class fangfa)
executing static_foo(static fangfa)
executing class_foo(<class '__main__.A'>,class fangfa2)
executing static_foo(static fangfa2)
'''

'''
4 类变量和实例变量
类变量就是供类使用的变量,实例变量就是供实例使用的.

这里p1.name="bbb"是实例调用了类变量,这其实和上面第一个问题一样,就是函数传参的问题,
p1.name一开始是指向的类变量name="aaa",但是在实例的作用域里把类变量的引用改变了,就变成了一个实例变量,
self.name不再引用Person的类变量name了.

可以看看下面的例子:
'''


class Person:
    name = "aaa"

p1 = Person()
p2 = Person()
p1.name = "bbb"
print p1.name  # bbb
print p2.name  # aaa
print Person.name  # aaa
Person.name = "bbb"
print Person.name # bbb


class Person:
    name = []

p1 = Person()
p2 = Person()
p1.name.append(1)
print p1.name  # [1]
print p2.name  # [1]
print Person.name  # [1]

"""
5 Python自省
这个也是python彪悍的特性.

自省就是面向对象的语言所写的程序在运行时,所能知道对象的类型.简单一句就是运行时能够获得对象的类型.比如type(),dir(),getattr(),hasattr(),isinstance().
"""

"""
6 字典推导式
可能你见过列表推导时,却没有见过字典推导式,在2.7中才加入的:

d = {key: value for (key, value) in iterable}

"""

"""
7 Python中单下划线和双下划线

__foo__:一种约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突.

_foo:一种约定,用来指定变量私有.程序员用来指定私有变量的一种方式.

__foo:这个有真正的意义:解析器用_classname__foo来代替这个名字,以区别和其他类相同的命名.
"""

"""
8 字符串格式化:%和.format

.format在许多方面看起来更便利.对于%最烦人的是它无法同时传递一个变量和元组.你可能会想下面的代码不会有什么问题:
"hi there %s" % name

但是,如果name恰好是(1,2,3),它将会抛出一个TypeError异常.为了保证它总是正确的,你必须这样做:
"hi there %s" % (name,)   # 提供一个单元素的数组而不是一个参数
"""

"""
9 迭代器和生成器
这个是stackoverflow里python排名第一的问题,值得一看: http://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python

这是中文版: http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/1/README.html
"""
mylist = [x*x for x in range(3)]
for i in mylist:
    print(i)

for i in mylist:
    print(i)
#所有你可以用在for...in...语句中的都是可迭代的:比如lists,strings,files...
# 因为这些可迭代的对象你可以随意的读取所以非常方便易用,但是你必须把它们的值放到内存里,当它们有很多值时就会消耗太多的内存.
# 上面的是迭代器 可多次调用，且常驻内存

#生成器也是迭代器的一种,但是你只能迭代它们一次.原因很简单,
# 因为它们不是全部存在内存里,它们只在要调用的时候在内存里生成:

mygenerator = (x*x for x in range(3))

for i in mygenerator:
    print(i)

for i in mygenerator:
    print(i)

#生成器和迭代器的区别就是用()代替[],还有你不能用for i in mygenerator第二次调用生成器:
# 首先计算0,然后会在内存里丢掉0去计算1,直到计算完4.

# Yield
'''
<generator object createGenerator at 0x0000000002F796C0>
test1
test2
0
test2
1
test2
4
'''
def createGenerator():
    mylist = range(3)
    print("test1")
    for i in mylist:
        print("test2")
        yield i*i

mygenerator = createGenerator()
print(mygenerator)

for i in mygenerator:
    print(i)


"""
10 *args and **kwargs
用*args和**kwargs只是为了方便并没有强制使用它们.

当你不确定你的函数里将要传递多少参数时你可以用*args.例如,它可以传递任意数量的参数:
"""
def print_everything(*args):
    for count,thing in enumerate(args):
        print '{0}. {1}'.format(count,thing)

print_everything('apple', 'banana', 'cabbage')

"""
相似的,**kwargs允许你使用没有事先定义的参数名:
"""

def table_things(**kwargs):
    for name,value in kwargs.items():
        print '{0} = {1}'.format(name,value)

table_things(apple='fruit', cabbage='vegetable')

def print_three_things(a,b,c):
    print 'a = {0}, b = {1}, c = {2}'.format(a, b, c)

mylist = ['aar', 'bab', 'cat']
print_three_things(*mylist)


"""
11 面向切面编程AOP和装饰器
"""

"""
12 鸭子类型
"""

"""
14 新式类和旧式类
"""

"""
16 单例模式
"""
class Singleton(object):
    def __new__(cls, *args, **kwargs):
        # 查看类是否有属性_instance
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kwargs)
        return cls._instance
class MyClass(Singleton):
    a = 1

class Borg(object):
    _state = {}
    def __new__(cls, *args, **kwargs):
        ob = super(Borg, cls).__new__(cls, *args, **kwargs)
        ob.__dict__ = cls._state
        return ob

class MyClass2(Borg):
    a = 1


def singleton(cls, *args, **kw):
    instances = {}

    def getinstance():
        if cls not in instances:
            instances[cls] = cls(*args, **kw)
        return instances[cls]

    return getinstance


@singleton
class MyClass:
    pass


# mysingleton.py
class My_Singleton(object):
    def foo(self):
        pass


my_singleton = My_Singleton()

# # to use
# from mysingleton import my_singleton

my_singleton.foo()

"""
17 Python中的作用域

本地作用域（Local）→当前作用域被嵌入的本地作用域（Enclosing locals）→全局/模块作用域（Global）→内置作用域（Built-in）
"""











